﻿using Quartz.Impl.Matchers;
using Quartz.Impl;
using Quartz;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using OrBitDataModule.Base;
using NLog;
using System.Collections.Specialized;

namespace OrBitDataModule.Common
{
    public class QuartzScheduler
    {
        private IScheduler scheduler;

        public QuartzScheduler()
        {
            NameValueCollection properties = new NameValueCollection
            {
                ["quartz.scheduler.instanceName"] = Guid.NewGuid().ToString()
            };
            var factory = new StdSchedulerFactory(properties);
            scheduler = factory.GetScheduler().GetAwaiter().GetResult();
        }
        /// <summary>
        /// 获取调度器
        /// </summary>
        /// <returns></returns>
        public IScheduler GetScheduler() => this.scheduler;

        /// <summary>
        /// 启动调度
        /// </summary>
        /// <returns></returns>
        public async void Start()
        {
            if (!scheduler.IsStarted)
            {
                await scheduler.Start();
            }
            await scheduler.ResumeAll();
        }

        /// <summary>
        /// 停止所有任务
        /// </summary>
        /// <returns></returns>
        public async void Pause()
        {
            await scheduler.PauseAll();
        }

        public async void Shutdown()
        {
            await RemoveAllTasks();
            await scheduler.Shutdown();
        }

        /// <summary>
        /// 固定间隔小时添加执行任务
        /// </summary>
        /// <param name="task"></param>
        /// <param name="hour"></param>
        /// <returns>返回任务的唯一标识符</returns>
        public async Task<string> AddTaskByHour(int hour, Action action)
        {
            string cronExpression = $"0 0 0/{hour} * * ? ";
            var result = await AddTask(cronExpression, action);
            return result;
        }

        public async Task<string> AddTask(TimeSpan timeSpan, Action action)
        {
            IJobDetail job = JobBuilder.Create<JobWrapper>()
                .UsingJobData("ActionType", action.GetType().AssemblyQualifiedName)
                .Build();

            ITrigger trigger = TriggerBuilder.Create()
                .WithSimpleSchedule(x => x.WithInterval(timeSpan).RepeatForever())
                .Build();

            job.JobDataMap.Put("Action", action);
            await scheduler.ScheduleJob(job, trigger);
            return job.Key.Name;
        }

        /// <summary>
        /// 固定间隔分钟添加执行任务
        /// </summary>
        /// <param name="task"></param>
        /// <param name="minute"></param>
        /// <returns>返回任务的唯一标识符</returns>
        public async Task<string> AddTaskByMinute(int minute, Action action)
        {
            string cronExpression = $"0 0/{minute} * * * ? *";
            var result = await AddTask(cronExpression, action);
            return result;
        }

        /// <summary>
        /// 固定间隔秒钟添加执行任务
        /// </summary>
        /// <param name="task"></param>
        /// <param name="second"></param>
        /// <returns>返回任务的唯一标识符</returns>
        public async Task<string> AddTaskBySecond(int second, Action action)
        {
            string cronExpression = $"0/{second} * * * * ? *";
            var result = await AddTask(cronExpression, action);
            return result;
        }


        /// <summary>
        /// 使用调度表达式添加执行任务
        /// </summary>
        /// <param name="task"></param>
        /// <param name="cronExpression"></param>
        /// <returns>返回任务的唯一标识符</returns>
        public async Task<string> AddTask(string cronExpression, Action action)
        {
            IJobDetail job = JobBuilder.Create<JobWrapper>()
                .UsingJobData("ActionType", action.GetType().AssemblyQualifiedName)
                .Build();

            ITrigger trigger = TriggerBuilder.Create()
                .WithCronSchedule(cronExpression)
                .Build();

            job.JobDataMap.Put("Action", action);
            await scheduler.ScheduleJob(job, trigger);
            return job.Key.Name;
        }

        /// <summary>
        /// 获取调度执行对象
        /// </summary>
        /// <param name="taskKey"></param>
        /// <returns></returns>
        public async Task<Action> GetTaskByKey(string taskKey)
        {
            var jobKey = new JobKey(taskKey);
            var jobDetail = await scheduler.GetJobDetail(jobKey);
            if (jobDetail != null)
            {
                Action action = jobDetail.JobDataMap.Get("Action") as Action;
                return action;
            }
            return null;
        }

        /// <summary>
        /// 获取所有正在执行中的调度
        /// </summary>
        /// <returns></returns>
        public async Task<Dictionary<string, Action>> GetAllExecutingTasks()
        {
            var executingJobs = await scheduler.GetCurrentlyExecutingJobs();
            var tasks = new Dictionary<string, Action>();

            foreach (var job in executingJobs)
            {
                Action action = job.JobDetail.JobDataMap.Get("Action") as Action;
                if (action != null)
                {
                    tasks.Add(job.JobDetail.Key.Name, action);
                }
            }
            return tasks;
        }

        /// <summary>
        /// 获取所有调度
        /// </summary>
        /// <returns></returns>
        public async Task<Dictionary<string, Action>> GetAllTasks()
        {
            var jobKeys = await scheduler.GetJobKeys(GroupMatcher<JobKey>.AnyGroup());
            var tasks = new Dictionary<string, Action>();
            foreach (var jobKey in jobKeys)
            {
                var jobDetail = await scheduler.GetJobDetail(jobKey);
                if (jobDetail != null)
                {
                    if (jobDetail.JobDataMap.Get("Action") is Action)
                    {
                        Action action = jobDetail.JobDataMap.Get("Action") as Action;
                        tasks.Add(jobDetail.Key.Name, action);
                    }
                }
            }
            return tasks;
        }

        /// <summary>
        /// 移除所有调度
        /// </summary>
        /// <returns></returns>
        public async Task RemoveAllTasks()
        {
            if (!scheduler.IsShutdown)
            {
                var jobKeys = await scheduler.GetJobKeys(GroupMatcher<JobKey>.AnyGroup());
                await scheduler.DeleteJobs(new List<JobKey>(jobKeys));
            }
        }

        public async Task<bool> RemoveTask(string taskKey)
        {
            JobKey jobKey = new JobKey(taskKey);
            var result = await scheduler.DeleteJob(jobKey);
            return result;
        }

        /// <summary>
        /// 恢复暂停的job
        /// </summary>
        /// <param name="taskKey"></param>
        /// <returns></returns>
        public Task ResumeTask(string taskKey) => scheduler.ResumeJob(new JobKey(taskKey));

        /// <summary>
        /// 暂停job
        /// </summary>
        /// <param name="taskKey"></param>
        /// <returns></returns>
        public Task PauseTask(string taskKey) => scheduler.PauseJob(new JobKey(taskKey));

        /// <summary>
        /// 取消一个正在运行中的调度，下一次调度不受到影响
        /// </summary>
        /// <param name="taskKey"></param>
        /// <returns></returns>
        public Task<bool> Interrupt(string taskKey) => scheduler.Interrupt(new JobKey(taskKey));
    }
    internal class JobWrapper : IJob
    {
        public async Task Execute(IJobExecutionContext context)
        {
            var action = context.JobDetail.JobDataMap["Action"] as Action;
            action?.Invoke();
            await Task.CompletedTask;
        }
    }
}
